﻿using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace KinonekoSoftware.Expressions
{
    public class ExpressionTree : INotifyPropertyChanged, INotifyPropertyChanging
    {

        private PropertyChangedEventHandler  PropertyChangedHandler;
        private PropertyChangingEventHandler PropertyChangingHandler;

        private string _name;
        private string _intro;

        /// <summary>
        /// 触发某个属性的数据已经变化的通知（这个通知能够影响绑定）
        /// </summary>
        /// <param name="propertyName">指定数据已经变化的属性名</param>
        protected internal void RaiseUpdated([CallerMemberName] string propertyName = null)
        {
            if (string.IsNullOrEmpty(propertyName)) return;
            PropertyChangedHandler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// 触发某个属性的数据正在变化的通知（这个通知不能够影响绑定）
        /// </summary>
        /// <param name="propertyName">指定数据正在变化的属性名</param>；
        protected void RaiseUpdating([CallerMemberName] string propertyName = null)
        {
            if (string.IsNullOrEmpty(propertyName)) return;
            PropertyChangingHandler?.Invoke(this, new PropertyChangingEventArgs(propertyName));
        }

        /// <summary>
        /// 设置指定属性的值，并且触发属性正在变更、属性已经变更通知。
        /// </summary>
        /// <param name="source">要触发的属性字段</param>
        /// <param name="value">新的值</param>
        /// <param name="name">属性名</param>
        /// <typeparam name="T">值的类型</typeparam>
        protected void SetValue<T>(ref T source, T value, [CallerMemberName] string name = "")
        {
            if (string.IsNullOrEmpty(name)) return;

            RaiseUpdating(name);
            source = value;
            RaiseUpdated(name);
        }
        

        public string Intro
        {
            get => _intro;
            set => SetValue(ref _intro, value);
        }


        public string Name
        {
            get => _name;
            set => SetValue(ref _name, value);
        }

        public required ObservableCollection<ExpressionNode> Blocks { get; init; }

        public event PropertyChangedEventHandler PropertyChanged
        {
            add => PropertyChangedHandler += value;
            remove => PropertyChangedHandler -= value;
        }

        public event PropertyChangingEventHandler PropertyChanging
        {
            add => PropertyChangingHandler += value;
            remove => PropertyChangingHandler -= value;
        }
    }
}